package orm

import (
	"encoding/json"
	"strings"

	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

type AtomSvrDefine struct {
	Atomsvrid        string                 `json:"atomsvrid"`
	Inputparamid     string                 `json:"inputparamid"`
	Inputparameter   map[string]interface{} `gorm:"-" json:"input-parameter"`
	Outputparamid    string                 `json:"outputparamid"`
	Outputparameter  map[string]interface{} `gorm:"-" json:"output-parameter"`
	Servicebindingid string                 `json:"-"`
	Servicebinding   Service                `gorm:"-" json:"service-binding"`
	Asdesc           string                 `json:"desc"`
	Asname           string                 `json:"name"`
	Catagoryid       string                 `json:"-"`
	CatagoryName     string                 `gorm:"-" json:"catagoryname"`
}

type CatagoryDef struct {
	Catagoryid   string
	Cgtype       string
	Intfname     string
	Intfabsname  string
	Parentid     string
	AtomSvrLst   []interface{} `gorm:"-" `
	Catagorydesc string
	ProcessSub   map[string]interface{} `gorm:"-" `
	ProcessLst   []interface{}          `gorm:"-" `
	Srcpath      string
}

type MappingFront struct {
	Type  string   `json:"type"`
	From  []string `json:"from"`
	Value string   `json:"value"`
	To    []string `json:"to"`
}

var db *gorm.DB
var err error

func init() {

	//postgres for publish
	//var dsn = "host=127.0.0.1 user=wzz password=wzz dbname=playbook port=5432 sslmode=disable TimeZone=Asia/Shanghai"
	//db, err = gorm.Open(postgres.Open(dsn), &gorm.Config{Logger: logger.Default.LogMode(logger.Info)})

	//sqlite for developer
	db, err = gorm.Open(sqlite.Open("playbook.db"), &gorm.Config{Logger: logger.Default.LogMode(logger.Info)})
}

func GetAtomSvrDefbyId(atomId string) (atomSvr AtomSvrDefine) {

	db.Table("atomsvrdefine").Where("atomsvrid = ?", atomId).Find(&atomSvr)

	return atomSvr
}

func GetAtomSvrDefbyName(atomname string) (atomSvr AtomSvrDefine, count int64) {

	db.Table("atomsvrdefine").Where("asname = ?", atomname).Find(&atomSvr).Count(&count)

	return atomSvr, count
}

func GetAtomSvrDefbyCataid(cataid string) (atomSvrLst []AtomSvrDefine, count int64) {

	db.Table("atomsvrdefine").Where("catagoryid = ?", cataid).Find(&atomSvrLst).Count(&count)
	// for i, _ := range atomSvrLst {
	// 	//获取原子服务出入参
	// 	atomSvrLst[i].Inputparameter = map[string]interface{}{"parameter": getAtomParameter(atomSvrLst[i].Inputparamid, "")}
	// 	atomSvrLst[i].Outputparameter = map[string]interface{}{"parameter": getAtomParameter(atomSvrLst[i].Outputparamid, "")}

	// 	//获取原子服务绑定
	// 	atomSvrLst[i].Servicebinding = getService(atomSvrLst[i].Servicebindingid)
	// }
	return atomSvrLst, count
}

func GetAtomSvrDef(atomSvr AtomSvrDefine) AtomSvrDefine {
	//获取原子服务出入参
	atomSvr.Inputparameter = map[string]interface{}{"parameter": getAtomParameter(atomSvr.Inputparamid, "")}
	atomSvr.Outputparameter = map[string]interface{}{"parameter": getAtomParameter(atomSvr.Outputparamid, "")}
	//获取原子服务绑定
	atomSvr.Servicebinding = getService(atomSvr.Servicebindingid)
	return atomSvr
}

func GetParamTreeByName(name string) map[string]interface{} {
	param, _ := GetParamByName(name)
	paramid := param.Parameterid
	return getAtomParameter(paramid, "")
}

func GetParamById(paramid string) Parameter {
	var param Parameter

	db.Table("parameter").Where("parameterid = ?", paramid).Find(&param)
	return param
}

func getAtomParameter(paramid string, relname string) map[string]interface{} {

	var param Parameter

	db.Table("parameter").Where("parameterid = ?", paramid).Find(&param)
	var paramMap = make(map[string]interface{})
	if relname == "" {
		paramMap["name"] = param.Name
	} else {
		paramMap["name"] = relname
	}
	paramMap["classPath"] = param.Classpath
	paramMap["optional"] = param.Optional
	paramMap["type"] = param.Type
	paramMap["paramid"] = param.Parameterid

	if param.Type == "Map" {
		if relname == "" {
			strarr := strings.Split(param.Classpath, ".")
			paramMap["mappingname"] = strarr[len(strarr)-1]
		} else {
			paramMap["mappingname"] = relname
		}

	} else if param.Type == "List" {
		paramMap["mappingname"] = paramMap["name"].(string) + "[]"
	} else {
		paramMap["mappingname"] = paramMap["name"]
	}

	var paramrel []Paramrelation
	var count int64
	db.Table("paramrelation").Where("parentparamid = ?", paramid).Find(&paramrel).Count(&count)

	if count == 0 {

		return paramMap
	}

	if param.Type == "List" {
		var paramrs []map[string]interface{}
		//list中元素为基本类型或子parameter，不允许使用javaMap(HashMap)
		pl := paramrel[0]
		//如果元素为parameter，对子参数进行递归遍历
		if len([]rune(pl.Subparamid)) == 32 {
			paramrsubs := getAtomParameter(pl.Subparamid, pl.Relname)
			paramrs = append(paramrs, paramrsubs)
			paramMap["parameter"] = paramrs
		} else {
			//如果子参数是基本类型，只需要新增一次
			var param = make(map[string]interface{})
			param["type"] = pl.Subparamid
			param["mappingname"] = pl.Subparamid
			paramrs = append(paramrs, param)
			paramMap["parameter"] = paramrs
		}

	} else if param.Type == "Map" {
		var paramrs []map[string]interface{}
		for _, pl := range paramrel {
			if pl.Reltype == "sub" {
				paramrsubs := getAtomParameter(pl.Subparamid, pl.Relname)
				paramrs = append(paramrs, paramrsubs)
			}
		}
		paramMap["parameter"] = paramrs
	}

	return paramMap
}

// 以列表形式查询原子服务映射参数
func GetAtomParameterList(paramid string) []string {
	params := getAtomParameter(paramid, "")
	var mappingparams []string
	getparamapping(params, &mappingparams, "")
	return mappingparams
}

func getparamapping(params map[string]interface{}, mappingparams *[]string, temp string) {
	if params["parameter"] == nil {
		res := temp + "." + params["mappingname"].(string)
		res = string([]byte(res)[1:len([]rune(res))])
		*mappingparams = append(*mappingparams, res)
		return
	}

	for _, param := range params["parameter"].([]map[string]interface{}) {
		getparamapping(param, mappingparams, temp+"."+params["mappingname"].(string))
	}
}

func CreateAtomSvr(atomSvr *AtomSvrDefine) {
	db.Table("atomsvrdefine").Create(atomSvr)
}

func getCatagorySub(parentid string, isloop bool, catagorySub *[]interface{}, isMap bool, allCgMap map[string]interface{}, cgtype string) {
	var catagoryLst []Catagory

	db.Table("catagorydefine").Where("parentid = ?", parentid).Find(&catagoryLst)

	for i, _ := range catagoryLst {
		if isMap {
			allCgMap[catagoryLst[i].Intfname] = catagoryLst[i]
		}
		if isloop {
			catagoryLst[i].CatagorySub = make([]interface{}, 0, 40)
			getCatagorySub(catagoryLst[i].Catagoryid, isloop, &catagoryLst[i].CatagorySub, isMap, allCgMap, cgtype)
		}
		//只有cgtype为2是，才需要查询原子服务列表
		if cgtype == "2" {
			atomsvrlst, count := GetAtomSvrDefbyCataid(catagoryLst[i].Catagoryid)
			if count > 0 {
				catagoryLst[i].AtomSvrLst = &atomsvrlst
			}
		}
		(*catagorySub) = append((*catagorySub), catagoryLst[i])
		//(*catagorySub)[catagoryLst[i].Intfname] = catagoryLst[i]

	}
}

func GetCgAllMap(cgtype string) map[string]interface{} {
	var allCgMap = make(map[string]interface{})
	var subCgLst = make([]interface{}, 0, 40)
	var catag Catagory

	db.Table("catagorydefine").Where("cgtype = ? and parentid = ?", cgtype, "root").Find(&catag)
	allCgMap[catag.Intfname] = catag

	getCatagorySub(catag.Catagoryid, true, &subCgLst, true, allCgMap, cgtype)

	return allCgMap
}

func GetCatagoryById(catagoryId string) Catagory {
	var catagory Catagory
	db.Table("catagorydefine").Where("catagoryid = ?", catagoryId).Find(&catagory)
	return catagory
}

func GetCatagory(cgtype string, parentid string) Catagory {
	var catag Catagory
	catag.CatagorySub = make([]interface{}, 0, 40)
	if parentid == "" {
		db.Table("catagorydefine").Where("cgtype = ? and parentid = ?", cgtype, "root").Find(&catag)
		getCatagorySub(catag.Catagoryid, true, &catag.CatagorySub, false, nil, cgtype)
	} else {
		db.Table("catagorydefine").Where("catagoryid = ?", parentid).Find(&catag)
		getCatagorySub(catag.Catagoryid, false, &catag.CatagorySub, false, nil, cgtype)
	}
	//cgtype:1-编排服务、2-原子服务、4-子流程
	if cgtype == "1" {
		processLst, count := getProcessbyCataid(catag.Catagoryid, false)
		if count > 0 {
			catag.ProcessLst = &processLst
		}
	} else if cgtype == "2" {
		atomsvrlst, count := GetAtomSvrDefbyCataid(catag.Catagoryid)
		if count > 0 {
			catag.AtomSvrLst = &atomsvrlst
		}
	} else if cgtype == "4" {
		processLst, count := getProcessbyCataid(catag.Catagoryid, true)
		if count > 0 {
			catag.ProcessLst = &processLst
		}
	}
	return catag
}

func GetCatagoryTree(cgtype string, parentid string) CatagoryDef {
	var catag CatagoryDef
	var isloop bool
	if parentid == "" {
		db.Table("catagorydefine").Where("cgtype = ? and parentid = ?", cgtype, "root").Find(&catag)
		isloop = true
	} else {
		db.Table("catagorydefine").Where("catagoryid = ?", parentid).Find(&catag)
		isloop = false
	}
	//cgtype:1-编排服务、2-原子服务、4-子流程
	if cgtype == "1" || cgtype == "4" {
		catag.ProcessLst = getCatagorySubTree(catag.Catagoryid, isloop, cgtype)
	} else if cgtype == "2" {
		catag.AtomSvrLst = getCatagorySubTree(catag.Catagoryid, isloop, cgtype)
	}
	return catag
}

func getCatagorySubTree(parentid string, isloop bool, cgtype string) []interface{} {

	var catagInfoLst []interface{}
	//cgtype:1-编排服务、2-原子服务、4-子流程
	if cgtype == "1" {
		processLst, count := getProcessbyCataid(parentid, false)
		if count > 0 {
			for _, process := range processLst {
				catagInfoLst = append(catagInfoLst, process)
			}
		}
	} else if cgtype == "2" {
		atomsvrlst, count := GetAtomSvrDefbyCataid(parentid)
		if count > 0 {
			for _, atomsvr := range atomsvrlst {
				catagInfoLst = append(catagInfoLst, atomsvr)
			}
		}
	} else if cgtype == "4" {
		processLst, count := getProcessbyCataid(parentid, true)
		if count > 0 {
			for _, process := range processLst {
				catagInfoLst = append(catagInfoLst, process)
			}
		}
	}
	var catagoryLst []CatagoryDef
	var subCatagCount int64
	db.Table("catagorydefine").Where("parentid = ?", parentid).Find(&catagoryLst).Count(&subCatagCount)
	if subCatagCount > 0 {
		for _, subCatag := range catagoryLst {
			if cgtype == "1" || cgtype == "4" {
				subCatag.ProcessLst = getCatagorySubTree(subCatag.Catagoryid, isloop, cgtype)
			} else if cgtype == "2" {
				subCatag.AtomSvrLst = getCatagorySubTree(subCatag.Catagoryid, isloop, cgtype)
			}
			catagInfoLst = append(catagInfoLst, subCatag)
		}
	}
	return catagInfoLst
}

func GetParamForCrtBean(parameterid string, tableType string) (param *Parameter, subparamLst *[]Parameter, paramrelst *[]Paramrelation) {

	var paramdef Parameter
	var subparamrelLstDef []Paramrelation
	var count int64
	var subparamLstDef []Parameter
	if tableType == "0" {
		db.Table("parameter").Where("parameterid = ?", parameterid).Find(&paramdef)
	} else if tableType == "1" {
		db.Table("paramdefine").Where("parameterid = ?", parameterid).Find(&paramdef)
	}
	// db.Table("parameter").Where("parameterid = ?", parameterid).Find(&paramdef)
	if paramdef.Type == "Map" && strings.Contains(paramdef.Classpath, ".") {
		subparamrelLstDef, count = GetParameterbyId(parameterid, "")

		var subparmlst []string
		for _, subparmrel := range subparamrelLstDef {
			subparmlst = append(subparmlst, subparmrel.Subparamid)
		}

		if count > 0 {
			if tableType == "0" {
				db.Table("parameter").Where("parameterid in  (?)", subparmlst).Find(&subparamLstDef)
			} else if tableType == "1" {
				db.Table("paramdefine").Where("parameterid in  (?)", subparmlst).Find(&subparamLstDef)
			}
			//db.Table("parameter").Where("parameterid in  (?)", subparmlst).Find(&subparamLstDef)
		}
	}
	param = &paramdef
	paramrelst = &subparamrelLstDef
	subparamLst = &subparamLstDef

	return param, subparamLst, paramrelst
}

func GetParamByName(name string) (param Parameter, count int64) {

	db.Table("parameter").Where("name = ?", name).Find(&param).Count(&count)
	return param, count
}

func GetParameterbyId(parentparamid string, subparamid string) (paramrelst []Paramrelation, count int64) {
	if subparamid == "" {
		db.Table("paramrelation").Where("parentparamid = ?", parentparamid).Find(&paramrelst).Count(&count)
	} else {
		db.Table("paramrelation").Where("parentparamid = ? and subparamid = ?", parentparamid, subparamid).Find(&paramrelst).Count(&count)
	}

	return paramrelst, count
}

func GetSubParameterbyName(parentparamid string, subName string) (param Paramrelation) {
	db.Table("paramrelation").Where("parentparamid = ? and name = ?", parentparamid, subName).Find(&param)
	return param
}

func GetAllActivity() []Activity {
	var acti []Activity

	db.Table("activity").Find(&acti)

	for i, _ := range acti {
		//获取原子服务出入参
		acti[i].Inputparameter = map[string]interface{}{"parameter": getParameter(acti[i].Inputparamid, "")}
		acti[i].Outputparameter = map[string]interface{}{"parameter": getParameter(acti[i].Outputparamid, "")}

		//获取原子服务绑定
		acti[i].Servicebinding = getService(acti[i].Servicebindingid)

		// acti[i].Inputparammapping = map[string][]Mapping{"massage-bean-mapping": []Mapping{}}
		// acti[i].Outputparammapping = map[string][]Mapping{"massage-bean-mapping": []Mapping{}}

	}

	return acti
}

func GetAtomInfo(atomId string) (AtomSvrDefine, Parameter, Parameter) {
	var atomsvr AtomSvrDefine
	var inparam Parameter
	var outparam Parameter
	db.Table("atomsvrdefine").Where("atomsvrid = ?", atomId).Find(&atomsvr)
	db.Table("parameter").Where("parameterid = ?", atomsvr.Inputparamid).Find(&inparam)
	db.Table("parameter").Where("parameterid = ?", atomsvr.Outputparamid).Find(&outparam)
	atomsvr.Servicebinding = getService(atomsvr.Servicebindingid)
	return atomsvr, inparam, outparam
}

//参数自动映射
func GetParamMapping(parammapping map[string][]interface{}) []MappingFront {

	//根据原子服务名称查询待匹配的参数id
	selectParams := parammapping["selectParam"]
	var paramlist []map[string]interface{}
	for _, selectparam := range selectParams {
		param := selectparam.(map[string]interface{})
		var act Activity
		atomname := strings.Split(param["atomName"].(string), ".")[0]
		db.Table("atomsvrdefine").Where("asname = ?", atomname).Find(&act)
		//按照前端需要的结构查询原子服务参数
		if param["paramType"] == "InnerReqDTO" {
			param["param"] = getAtomParameterList(act.Inputparamid, param["atomName"].(string))
		} else if param["paramType"] == "InnerRespDTO" {
			param["param"] = getAtomParameterList(act.Outputparamid, param["atomName"].(string))
		}
		paramlist = append(paramlist, param)
	}

	inputParamMappings := parammapping["inputParamMapping"]
	var res []MappingFront
	//循环处理原子服务的每一个参数
	for _, inputParamMapping := range inputParamMappings {
		resByre, _ := json.Marshal(inputParamMapping)
		var mappedparam MappingFront
		json.Unmarshal(resByre, &mappedparam)
		mappingto := mappedparam.To
		toname := mappingto[len(mappingto)-1]
		mapflag := false
		//循环处理被选中的原子服务
		for _, param := range paramlist {
			fromParamList := param["param"].([][]string)
			//循环处理当前原子服务的每一个参数
			for i := 0; i < len(fromParamList); i++ {
				fromparam := fromParamList[i]
				fromname := fromparam[len(fromparam)-1]
				if fromname == toname {
					mappedparam.From = fromparam
					mapflag = true
					break
				}
			}
			if mapflag {
				break
			}
		}
		res = append(res, mappedparam)
	}

	return res
}

func getAtomParameterList(paramid string, atomName string) [][]string {
	params := getAtomParameter(paramid, "")
	var mappingparams [][]string
	var temp []string
	temp = append(temp, atomName)
	getparamappingList(params, &mappingparams, temp)
	return mappingparams
}

func getparamappingList(params map[string]interface{}, mappingparams *[][]string, temp []string) {
	if params["parameter"] == nil {
		res := temp
		res = append(res, params["mappingname"].(string))
		*mappingparams = append(*mappingparams, res)
		return
	}

	for _, param := range params["parameter"].([]map[string]interface{}) {
		getparamappingList(param, mappingparams, append(temp, params["mappingname"].(string)))
	}
}

//参数自动映射
func GetParamMapping1(parammapping map[string]interface{}) []MappingFront {

	mappingtype := parammapping["mappingtype"].(string)

	selectParams := parammapping["selectParam"]
	resByre, _ := json.Marshal(selectParams)
	var selectParamList [][]string
	json.Unmarshal(resByre, &selectParamList)

	inputParamMappings := parammapping["inputParamMapping"]
	resByreMapping, _ := json.Marshal(inputParamMappings)
	var mappedparamList []MappingFront
	json.Unmarshal(resByreMapping, &mappedparamList)

	var res []MappingFront
	//循环处理原子服务的每一个参数
	for _, mappedparam := range mappedparamList {
		var mappingto []string
		var toname string
		if mappingtype == "inputmapping" {
			mappingto = mappedparam.To
			toname = mappingto[len(mappingto)-1]
		} else if mappingtype == "outputmapping" {
			mappingto = mappedparam.From
			toname = mappingto[len(mappingto)-1]
		}

		//循环处理被选中的参数
		for _, param := range selectParamList {
			fromName := param[len(param)-1]
			if fromName == toname {
				if mappingtype == "inputmapping" {
					mappedparam.From = param
				} else if mappingtype == "outputmapping" {
					mappedparam.To = param
				}

			}
		}
		res = append(res, mappedparam)
	}

	return res
}
